﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SCEM.DTO;
using SCEM.DataLayer;

namespace SCEM.ControleEstoque
{
    /// <summary>
    /// Classe de controle de estoque.
    /// </summary>
    public class EstoqueControle
    {
        /// <summary>
        /// Insere uma quantidade do produto no estoque.
        /// </summary>
        /// <param name="idProduto">O id do produto a ser inserido no estoque.</param>
        /// <param name="quantidade">A quantidade a ser inserida do produto.</param>
        /// <returns>Retorna 0 caso sucesso, -1 caso ocorra um erro no banco.</returns>
        public int InsereProdutoEstoque(string idProduto, int quantidade)
        {
            ProdutoDAO produtoDAO = new ProdutoDAO();

            // Histórico
            HistoricoEstoqueDAO historicoDAO = new HistoricoEstoqueDAO();
            HistoricoEstoqueDTO historicoDTO = new HistoricoEstoqueDTO();
            historicoDTO.NomeResponsavel = "Usuario";
            historicoDTO.DataModificacao = DateTime.Now;
            historicoDTO.QuantidadeAlterada = quantidade;
            historicoDTO.IdProduto = idProduto;

            ProdutoDTO produtoDTO = (ProdutoDTO)produtoDAO.Get(idProduto);
            if (produtoDTO == null)
                return -1; //caso de erro

            produtoDTO.Quantidade = produtoDTO.Quantidade + quantidade;
            IDTO<Produto> produto = produtoDAO.Update(produtoDTO);
            if (produto == null)
                return -1;
            else
            {
                HistoricoEstoqueDTO itemHistorico = (HistoricoEstoqueDTO)historicoDAO.Save(historicoDTO);
                if (itemHistorico != null)
                    return 0;
                else
                    return -1;
            }
        }

        /// <summary>
        /// Retira uma quantidade do produto no estoque
        /// </summary>
        /// <param name="idProduto">O id do produto a ser retirado do estoque.</param>
        /// <param name="quantidade">A quantidade a ser retirada do produto.</param>
        /// <returns> Retorna 0 caso sucesso, retorna -1 caso quantidade retirada é maior que a quantidade existente no estoque (não é alterada a quantidade do produto), retorna -2 erro banco.</returns>
        public int RetiraProdutoEstoque(string idProduto, int quantidade)
        {
            ProdutoDAO produtoDAO = new ProdutoDAO();

            //Histórico
            HistoricoEstoqueDAO historicoDAO = new HistoricoEstoqueDAO();
            HistoricoEstoqueDTO historicoDTO = new HistoricoEstoqueDTO();
            historicoDTO.NomeResponsavel = "Usuario";
            historicoDTO.DataModificacao = DateTime.Now;
            historicoDTO.QuantidadeAlterada = -quantidade;
            historicoDTO.IdProduto = idProduto;

            ProdutoDTO produtoDTO = (ProdutoDTO)produtoDAO.Get(idProduto);
            if (produtoDTO == null)
                return -2; //caso de erro
            if (produtoDTO.Quantidade < quantidade)
                return -1; //caso quantidade retirada é maior que a quantidade existente no estoque.
           
            produtoDTO.Quantidade = produtoDTO.Quantidade - quantidade;
            ProdutoDTO produto = (ProdutoDTO)produtoDAO.Update(produtoDTO);
            if (produto == null)
                return -2;
            else
            {
                HistoricoEstoqueDTO itemHistorico = (HistoricoEstoqueDTO)historicoDAO.Save((HistoricoEstoqueDTO)historicoDTO);
                if (itemHistorico != null)
                    return 0;
                else
                    return -2;
            }
        }

        /// <summary>
        /// Lista os produtos cuja quantidade existente no estoque é menor que a quantidade mínima do produto. 
        /// </summary>
        /// <param name="pageNumber">O número da página >= 1.</param>
        /// <param name="resultsPerPage">Quantidade de resultados a serem exibidos por página.</param>
        /// <returns>A lista de produtos que satisfazem a condição.</returns>
        public List<ProdutoDTO> ListaProdutosAlerta(int pageNumber, int resultsPerPage)
        {
            ProdutoDAO produtoDAO = new ProdutoDAO();

            int pageNumberIndex = pageNumber - 1;
            if (pageNumberIndex < 0)
                return new List<ProdutoDTO>();

            List<ProdutoDTO> listaProdutosAlerta = produtoDAO.ListarProdutosAlerta();
            int skip = pageNumberIndex * resultsPerPage;

            if (listaProdutosAlerta.Count() <= skip)
                return new List<ProdutoDTO>();
            else if (listaProdutosAlerta.Count() < skip + resultsPerPage)
                return listaProdutosAlerta.GetRange(skip, listaProdutosAlerta.Count() - skip);
            else
                return listaProdutosAlerta.GetRange(skip, resultsPerPage);
        }

        /// <summary>
        /// Lista os produtos cuja quantidade existente no estoque é maior que 0. 
        /// </summary>
        /// <param name="pageNumber">O número da página >= 1.</param>
        /// <param name="resultsPerPage">Quantidade de resultados a serem exibidos por página.</param>
        /// <returns>A lista de produtos que satisfazem a condição.</returns>
        public List<ProdutoDTO> ListaProdutosEstoque(int pageNumber, int resultsPerPage)
        {
            ProdutoDAO produtoDAO = new ProdutoDAO();

            int pageNumberIndex = pageNumber - 1;
            if (pageNumberIndex < 0)
                return new List<ProdutoDTO>();

            List<ProdutoDTO> listaProdutosEstoque = produtoDAO.ListarProdutosEstoque();
            int skip = pageNumberIndex * resultsPerPage;

            if (listaProdutosEstoque.Count() <= skip)
                return new List<ProdutoDTO>();
            else if (listaProdutosEstoque.Count() < skip + resultsPerPage)
                return listaProdutosEstoque.GetRange(skip, listaProdutosEstoque.Count() - skip);
            else
                return listaProdutosEstoque.GetRange(skip, resultsPerPage);
        }

        /// <summary>
        /// Verifica se o produto está disponível no estoque (quantidade > 0).
        /// </summary>
        /// <param name="idProduto">O id do produto cuja disponibilidade deseja ser verificada.</param>
        /// <returns><code>true</code> se o produto está disponível, <code>false</code> caso contrário.</returns>
        public bool VerificaDisponibilidadeProduto(string idProduto)
        {
            ProdutoDAO produtoDAO = new ProdutoDAO();
            ProdutoDTO produto = (ProdutoDTO)produtoDAO.Get(idProduto);
            if (produto == null)
                return false;
            if (produto.Quantidade > 0 && produto.Ativo)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Serviço oferecido que retorna uma lista com o histórico do estoque em um determinado período escolhido pelo usuário.
        /// </summary>
        /// <param name="idProduto">A identificação do produto.</param>
        /// <param name="dataInicio">Data inicial a ser considerada.</param>
        /// <param name="dataFim">Data final a ser considerada.</param>
        /// <param name="pageNumber">Número da página.</param>
        /// <param name="resultsPerPage">Quantidade de resultados por página.</param>
        /// <returns>Os itens do histórico requisitados pelo usuário.</returns>
        public List<HistoricoEstoqueDTO> BuscarHistoricoProdutos(string idProduto, DateTime dataInicio, DateTime dataFim, int pageNumber, int resultsPerPage)
        {
            HistoricoEstoqueDAO historicoEstoqueDAO = new HistoricoEstoqueDAO();
            int pageNumberIndex = pageNumber - 1;
            if (pageNumberIndex < 0)
                return new List<HistoricoEstoqueDTO>();

            List<HistoricoEstoqueDTO> listaHistoricoEstoque = historicoEstoqueDAO.buscarHistoricoProdutos(idProduto, dataInicio, dataFim);
            int skip = pageNumberIndex * resultsPerPage;

            if (listaHistoricoEstoque.Count() <= skip)
                return new List<HistoricoEstoqueDTO>();
            else if (listaHistoricoEstoque.Count() < skip + resultsPerPage)
                return listaHistoricoEstoque.GetRange(skip, listaHistoricoEstoque.Count() - skip);
            else
                return listaHistoricoEstoque.GetRange(skip, resultsPerPage);
        }

    }
}
